package cn.coufran.springboot.starter.api.config;

import cn.coufran.commons.Result;
import cn.coufran.commons.exception.ServiceException;
import jakarta.servlet.ServletException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

/**
 * 业务异常全局处理配置
 *
 * @author Coufran
 * @version 1.1.0
 * @since 1.3.0
 */
@RestControllerAdvice
public class ExceptionHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionHandler.class);

    /**
     * 业务异常类
     */
    private Collection<Class<? extends RuntimeException>> serviceExceptionClasses = new ArrayList();

    /**
     * 设置业务异常类
     *
     * @param serviceExceptionClasses 业务异常类
     */
    @Autowired(required = false)
    public void setServiceExceptionClasses(Collection<Class<? extends RuntimeException>> serviceExceptionClasses) {
        this.serviceExceptionClasses.addAll(serviceExceptionClasses);
    }

    /**
     * 添加业务异常类
     *
     * @param serviceExceptionClasses 业务异常类
     */
    public void addServiceExceptionClass(Class<? extends RuntimeException>... serviceExceptionClasses) {
        this.serviceExceptionClasses.addAll(Arrays.asList(serviceExceptionClasses));
    }

    /**
     * 处理异常
     *
     * @param e 异常对象
     * @return Result对象
     */
    @org.springframework.web.bind.annotation.ExceptionHandler(Exception.class)
    public Result handlerException(Exception e) throws Exception {
        // @see DefaultHandlerExceptionResolver
        if (e instanceof ServletException || e.getClass().getPackage().getName().startsWith("org.springframework.")) {
            throw e;
        }
        String message = "未知异常，请稍候重试";
        String code = null;
        if (isServiceException(e)) { // 如果是广义的业务异常
            message = e.getMessage();
            if (e instanceof ServiceException) { // 如果是标准业务异常
                code = ((ServiceException) e).getCode();
            }
        } else {
            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("{}", e.toString());
            }
        }
        if (code == null) {
            code = Result.CODE_ERROR;
        }
        return Result.error(code, message);
    }

    /**
     * 判断异常对象是不是配置的业务异常
     *
     * @param e 异常对象
     * @return 是业务异常返回true，否则返回false
     */
    private boolean isServiceException(Throwable e) {
        if (serviceExceptionClasses == null || serviceExceptionClasses.isEmpty()) {
            return false;
        }
        for (Class<? extends RuntimeException> serviceExceptionClass : serviceExceptionClasses) {
            if (serviceExceptionClass.isInstance(e)) {
                return true;
            }
        }
        return false;
    }
}
